/** by YPC
*/
#include "xMappingNode.h"
#include "xNodeType.h"
#include "xNodeType_vmclone.h"
#include "vmLibrary.h"
#include "xParameterPack.h"
#include "all_entries.h"
#include "xInMappingPort.h"
#include "xOutMappingPort.h"

using namespace std; 
void xNodeType_vmclone::setupPorts() {

	// one input port
	_parent->_inports.push_back(new xInMappingPort("vm",_parent));

	//這段是為了給vm clone之後可以得到vm的inport屬性
	// why cube ubvm?
	vmdescriptor* vd = vmLibrary::instance().get_vmdescriptor("CUBE_UBVM") ;
	for( auto it = vd->inputParameters.begin(); it < vd->inputParameters.end(); ++it ) {
		xInMappingPort *ip = new xInMappingPort(_parent,
			it->name,
			it->type,
			it->klass,
			it->defaultValue,
			it->category) ;
		_parent->_inports.push_back(ip);
	}

	// standard output ports that copied from ubvm 
	//vmdescriptor* _vd = vmLibrary::getInstance()->get_vmdescriptor("CUBE_UBVM") ;
	for( auto it = vd->outputParameters.begin(); it < vd->outputParameters.end(); ++it ) {
		xOutMappingPort *op = new xOutMappingPort(_parent,
												 it->name,
												 it->type,
												 it->klass,
												 it->defaultValue,
												 it->category) ;
		_parent->_outports.push_back(op);
	}
	
}
void xNodeType_vmclone::createMappedObject() {

	//先從inport 0得到vm的指標
	xMappingNode *node = this->getParent();
	xInMappingPort *inp = node->getInPort(0);
	xParameter xp=inp->toXParameter();
	assert(xp.type=="vm");
	_vm=xp.val_vm;
	
	xParameterPack xpp ;
	xpp.no = 0 ;
	for (int i = 1 ; i < node->getInportSize(); i++) {
		inp = node->getInPort(i);
		xp = inp->toXParameter();
		xpp.no ++ ;
		xpp.paras.push_back(xp); 
		if (inp->getLink() != NULL) {
			xpp.para_onoff.push_back(true);
		} else {
			xpp.para_onoff.push_back(false);
		}
	}

	_vm->updateByXpp(xpp); // 

}
bool xNodeType_vmclone::update() {
	// do nothing when update() is called ;
	return true ;
}
xParameter xNodeType_vmclone::toXParameter(string type, xOutMappingPort * linkedop) {
	// when this node is connected to a parent P at higher level
	// P can ask for its xParameter
	xParameter xp ;
	
	int i = linkedop->getIndexOfParent();
	assert(i>=0) ;

	switch(i) {
		case 0: 
					xp.type = T_VM ;
					assert(_vm != NULL);
					xp.val_vm = _vm ;
					return xp ;
		case 1: 
					xp.type = T_STRING ;
					xp.val_string = _vm->get_vm_name(); // varname
					return xp ;
		case 2: // varname_position
					xp.type = T_INT ;
					xp.val_int = _vm->get_vm_name_position();
					return xp ;
		case DIVA_VM::RC+1: 	// rx 
					xp.type = TP_FLOAT ;
					xp.val_float_ptr = _vm->get_vm_rx();
					return xp ;
		case DIVA_VM::RC+2 : // ry ;
					xp.type = TP_FLOAT ;
					xp.val_float_ptr = _vm->get_vm_ry();
					return xp ;
		case DIVA_VM::RC+3 : 
					xp.type = TP_FLOAT ;
					xp.val_float_ptr = _vm->get_vm_rz();
					return xp ;// rz 
		case DIVA_VM::SIZE+1 : // sizex
					xp.type = TP_FLOAT ;
					xp.val_float_ptr = _vm->get_vm_sizex();
					return xp ;
		case DIVA_VM::SIZE+2 : // sizey 
					xp.type = TP_FLOAT ;
					xp.val_float_ptr = _vm->get_vm_sizey();
					return xp ;
		case DIVA_VM::SIZE+3:  // sizez
					xp.type = TP_FLOAT ;
					xp.val_float_ptr = _vm->get_vm_sizez();
					return xp ; 
		case DIVA_VM::SCALE+1: // scalesizex 
					xp.type = TP_DOUBLE ;
					xp.val_double_ptr = _vm->get_vm_sizexscale();
					return xp ;
		case DIVA_VM::SCALE+2: // scalesizey 
					xp.type = TP_DOUBLE ;
					xp.val_double_ptr = _vm->get_vm_sizeyscale();
					return xp ;
		case DIVA_VM::SCALE+3: // scalesizez
					xp.type = TP_DOUBLE ;
					xp.val_double_ptr = _vm->get_vm_sizezscale();
					return xp ;
		case DIVA_VM::RGB+1 : // r
					xp.type = TP_DOUBLE ;
					xp.val_double_ptr = _vm->get_vm_r();
					return xp ;
		case DIVA_VM::RGB+2 : // g
					xp.type = TP_DOUBLE ;
					xp.val_double_ptr = _vm->get_vm_g();
					return xp ;
		case DIVA_VM::RGB+3:  // b
					xp.type = TP_DOUBLE ;
					xp.val_double_ptr = _vm->get_vm_b();
					return xp ;
		case DIVA_VM::TRANS+1:// transparency
					assert(false); // under construction
		case DIVA_VM::ROTATE+1 : // yaw 
					xp.type = TP_INT ;
					xp.val_int_ptr = _vm->get_vm_yaw();
					return xp ; 
		case DIVA_VM::ROTATE+2 : // pitch 
					xp.type = TP_INT ;
					xp.val_int_ptr = _vm->get_vm_pitch();
					return xp ; 
		case DIVA_VM::ROTATE+3 : // roll
					xp.type = TP_INT ;
					xp.val_int_ptr = _vm->get_vm_roll();
					return xp ; 
		case DIVA_VM::QUAT+1:	// quaternion
					assert(false); // under construction
		case DIVA_VM::CLICKMSG+1 : // clickmsg
					xp.type = TP_STRING ;
					xp.val_string_ptr = _vm->get_vm_clickmsg();
					return xp ; 
		case DIVA_VM::CLICKMSG+2: // clickmsg_pos
					xp.type = T_INT ;
					xp.val_int = _vm->get_vm_clickmsg_position();
					return xp ;
		default:
			assert(false); // should not reach here
			return xp ;
	}
}

string xNodeType_vmclone::toMDString(MDSType type) {
	ostringstream MDSstr ;
	if ( type == xNodeType::NormalMDSFormat ){
		MDSstr << "node "<<  _parent->getSerialNo() << " vmclone " << "NULL" << " " << "NULL" << endl ; 
	} else if ( type == xNodeType::ParameterizedMDSFormat ){
		MDSstr << "ADD_NODE " <<"node "<< "SN" <<_parent->getSerialNo() << " vmclone " << "NULL" << " " << "NULL" << endl ; 
	} else {
		assert(false);
	}
	
	return MDSstr.str();
}
int  xNodeType_vmclone::parseMDString(vector<string>& tokens, int start_index) {
	int i = start_index ;
	assert(tokens[i] == "node");
	string serialno = tokens[i+1] ;
	assert(tokens[i+2] == "vmclone");
	string nodetype = tokens[i+3] ; assert(nodetype == "NULL");
	string wopname = tokens[i+4] ; assert(nodetype == "NULL");

	return 5 ;
}
string xNodeType_vmclone::valid_rhs_pair[][2] = { 
// in a VM node, the outport can only have type (int*, double*, tostring*	
"int*", "wop", 
"double*", "wop",
"dontcare", "tostring*"
};

bool xNodeType_vmclone::verify_rhs_link(xOutMappingPort *left, xInMappingPort *right, xNodeType* rightnode) {

	if (left->getType() == right->getType()) return true ;
	return check_valid_pair(valid_rhs_pair, sizeof(valid_rhs_pair)/(sizeof(string)*2),
							left->getType(), right->getType());
}
bool xNodeType_vmclone::verify_lhs_link(xOutMappingPort *left, xNodeType* leftnode, xInMappingPort *right) {
	
	return true ; // when a link is on the left hand side of this node
	              // we have the leftnode to check for the validity
}

